home *** CD-ROM | disk | FTP | other *** search
/ Atari Forever 4 / Atari Forever 4 / Atari Forever 4.iso / SERIE_AI / AI_017 / INTERNET.TOS / SOFTWARE / TUWTCPSR / UDP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-19  |  8.8 KB  |  300 lines

  1. #include <stdlib.h>
  2. #include <time.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <tos.h>
  6. #include "pktdrv.h"
  7. #include "ip.h"
  8. #include "icmp.h"
  9. #include "timer.h"
  10. #include "udp.h"
  11. #include "inetcust.h"
  12. #include "mbuf.h"
  13.  
  14. #include "nettrace.h"
  15.  
  16. #define Bconws(x) dpy = x;while(*dpy)(Bconout(2,*dpy++))
  17.  
  18. static char *dpy;
  19.  
  20. #define noDEBUGDROP
  21. #define noDEBUGRECV
  22. #define noDEBUGOPN
  23. #define noDEBUGCLS
  24. #define noDEBUGWR
  25.  
  26. #define min(a,b) ((a) < (b) ? (a) : (b))
  27.  
  28. UDP_CTL  *udp_list = NULL;
  29. UDP_CTL **udp_tab;
  30. int          udp_tablen = 0;
  31. extern char *udp_buffers;
  32. int udp_handler(PACKET *,int,INADDR);
  33. int udp_du_handler(IP *);
  34. void udp_droppacket(TIMER);
  35. u_short udp_newport(void);
  36. long udp_counts[2] = {0,0};
  37.  
  38. int udp_init(void)
  39. {
  40. register int i;
  41.     udp_list = NULL;
  42.     udp_tablen = UDP_MAXPORTS;
  43.     udp_tab = (UDP_CTL **)getmem((size_t)udp_tablen*sizeof(UDP_CTL *));
  44.     if(!udp_tab) return(FALSE);
  45.     for(i=0; i<udp_tablen; i++)
  46.         udp_tab[i] = NULL;
  47.     if(!ip_open(IP_UDP,udp_handler,udp_du_handler))
  48.     {
  49.         freemem(udp_tab);
  50.         return(FALSE);
  51.     }
  52.     return(TRUE);
  53. }
  54.  
  55. int udp_exit(void)
  56. {
  57. int i;
  58.  
  59.     if(udp_tab)
  60.     {
  61.         for(i=0;i<udp_tablen;i++)
  62.             if(udp_tab[i]) udp_close(i);
  63.         free(udp_tab);
  64.         udp_tab = NULL;
  65.         udp_tablen = 0;
  66.     }
  67.     return(ip_close(IP_UDP));
  68. }
  69.  
  70.  
  71. int udp_handler(PACKET *pkt,int len,INADDR fhost)
  72. {
  73. UDP_CTL *p_udpctl;
  74. IP         *p_ip;
  75. register UDP *p_udp;
  76. TCP_PSEUDO tcp_ph;
  77. u_short csum;
  78. unsigned plen;
  79.  
  80.     /* First let's verify that it's a valid UDP packet. */
  81.     p_ip = ip_head(pkt);
  82.     p_udp = udp_head(p_ip);
  83.     
  84.     plen = p_udp->length;
  85.  
  86.     if(plen > len)
  87.     {
  88. #ifdef DEBUGRECV
  89. printf("invalid packet %u,%u\n",plen,len);
  90. #endif
  91.         ip_free(pkt);
  92.         return(FALSE);
  93.     }
  94.  
  95.     csum = p_udp->chksum;
  96.     if(csum)
  97.     {
  98.         tcp_ph.src = fhost;
  99.         tcp_ph.dst = p_ip->dst_inaddr;
  100.         tcp_ph.protocol = IP_UDP;
  101.         tcp_ph.length  = len;
  102.  
  103.         p_udp->chksum = ~chksum((u_short *)&tcp_ph,(u_short)sizeof(TCP_PSEUDO),0);
  104.         p_udp->chksum = chksum((u_short *)p_udp,len,0);
  105.         if(csum != p_udp->chksum && !(csum == 0xffff && p_udp->chksum == 0))
  106.         {
  107. #ifdef DEBUGRECV
  108. printf("bad checksum %04x->%04x\n",csum,p_udp->chksum);
  109. #endif
  110.             ip_free(pkt);
  111.             return(FALSE);
  112.         }
  113.     }
  114.  
  115.     /* ok, accept it. run through the demux table and try to upcall it */
  116.     for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  117.     {
  118.         if(p_udpctl->lcl_port && (p_udpctl->lcl_port != p_udp->dst_port))
  119.             continue;
  120.  
  121.         if(p_udpctl->upcall)
  122.         {
  123. #ifdef DEBUGRECV
  124. printf("pkt [%d] from %8lx.%u to port %u\n",len,fhost,p_udp->src_port,p_udpctl->lcl_port);
  125. #endif
  126.             p_udpctl->fhost = fhost;
  127.             p_udpctl->fgn_port = p_udp->src_port;
  128.             p_udpctl->data_len = len - sizeof(UDP);
  129.             p_udpctl->data = (char *)p_udp+sizeof(UDP);
  130.             if(p_udpctl->pkt)
  131.             {
  132. #ifdef DEBUGRECV
  133. printf("packet overrun\n");
  134. #endif
  135.                 ip_free(p_udpctl->pkt);            /* throw away old packet */
  136.                 p_udpctl->udp_err = UDP_OVR;    /* signal overrun */
  137.             }
  138.             else
  139.                 p_udpctl->udp_err = UDP_OK;
  140.             p_udpctl->pkt = NULL;
  141.                 ip_free(pkt);            /* throw away old packet */
  142.             udp_counts[0]++;
  143.             tm_stop(p_udpctl->udp_tm);
  144.             tm_set(UDP_KEEPPKT,udp_droppacket,p_udpctl->udp_tm);
  145.             (p_udpctl->upcall)(p_udpctl->handle,(char *)p_udp+sizeof(UDP), len-(int)sizeof(UDP));
  146.         }
  147.         else
  148.         {
  149.             p_udpctl->fhost = 0L;
  150.             p_udpctl->fgn_port = 0;
  151.             p_udpctl->data_len = 0;
  152.             p_udpctl->data = NULL;
  153.             p_udpctl->pkt = NULL;
  154.             ip_free(pkt);
  155.         }
  156.         return(TRUE);
  157.     }
  158.         ip_free(pkt);
  159.         return(FALSE);
  160.  
  161.  
  162.     /* what a crock. check if the packet was sent to an ip
  163.         broadcast address. If it was, don't send a destination
  164.         unreachable.
  165.     */
  166.  
  167.     if((p_ip->dst_inaddr == 0xffffffffL)) /* Physical cable broadcast addr*/
  168.     {
  169.         ip_free(pkt);
  170.         return(FALSE);
  171.     }
  172.  
  173.     /* send destination unreachable */
  174.     icmp_dstun(p_ip->src_inaddr,p_ip,ICMP_DSTPORT);
  175.  
  176.     ip_free(pkt);
  177.     return(FALSE);
  178. }
  179.  
  180.  
  181.  
  182. /* This routine drops a UDP packet from the udp-port, if nobody */
  183. /* fetched the data within the UDP_KEEPPKT timeout                 */
  184.  
  185. void udp_droppacket(TIMER tm)
  186. {
  187. UDP_CTL *p_udpctl;
  188.  
  189.     p_udpctl = udp_list;
  190.     while(p_udpctl)
  191.     {
  192.         if(p_udpctl->udp_tm == tm)
  193.         {
  194.             if(p_udpctl->pkt)
  195.             {
  196. #ifdef DEBUGDROP
  197. printf("UDP: dropping packet from %8lx.%u\n",p_udpctl->fhost,p_udpctl->fgn_port);
  198. #endif
  199.                 p_udpctl->fhost = 0L;
  200.                 p_udpctl->fgn_port = 0;
  201.                 p_udpctl->data_len = 0;
  202.                 p_udpctl->data = NULL;
  203.                 ip_free(p_udpctl->pkt);
  204.                 p_udpctl->pkt = NULL;
  205.                 p_udpctl->udp_err = UDP_MISS;
  206.             }
  207.         }
  208.         p_udpctl = p_udpctl->next;
  209.     }
  210.     return;
  211. }
  212.  
  213.  
  214. UDP_CTL *udp_getctl(u_short udp)
  215. {
  216.  
  217.     if(udp >= udp_tablen) return(NULL);
  218.     return(udp_tab[udp]);
  219. }
  220.  
  221.  
  222.  
  223. /* This routine drops a udp packet from its port */
  224.  
  225. int udp_free(u_short udp)
  226. {
  227. UDP_CTL *p_udpctl;
  228.  
  229.     if(udp >= udp_tablen) return(-1);
  230.     p_udpctl = udp_tab[udp];
  231.     if(p_udpctl && p_udpctl->pkt)
  232.     {
  233.         p_udpctl->fhost = 0L;
  234.         p_udpctl->fgn_port = 0;
  235.         p_udpctl->data_len = 0;
  236.         p_udpctl->data = NULL;
  237.         tm_stop(p_udpctl->udp_tm);
  238.         ip_free(p_udpctl->pkt);
  239.         p_udpctl->pkt = NULL;
  240.         p_udpctl->udp_err = UDP_OK;
  241.         return(udp);
  242.     }
  243.     return(-1);
  244. }
  245.  
  246.  
  247.  
  248. /* This routine handles incoming UDP destination unreachable packets.
  249.     They're handed to it by the internet layer. It demultiplexes
  250.     the incoming packet based on the local port and upcalls the
  251.     appropriate routine. */
  252.  
  253. int udp_du_handler(IP *p_ip)
  254. {
  255. register UDP *p_udp;
  256. register UDP_CTL *p_udpctl;
  257.  
  258. Bconws("UDP destunreachable\r");
  259.     p_udp = udp_head(p_ip);
  260.  
  261.     for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  262.     {
  263.         if(p_udpctl->lcl_port && (p_udpctl->lcl_port != p_udp->src_port))
  264.             continue;
  265.  
  266.         p_udpctl->udp_err = UDP_NORECV;
  267.         if(p_udpctl->upcall)
  268.             p_udpctl->upcall(p_udpctl->handle,NULL,UDP_NORECV);
  269.         return(TRUE);
  270.     }
  271.     return(FALSE);
  272. }
  273.  
  274.  
  275. /* This routine removes a udp-port from the udp connections list    */
  276. /* and frees all related memory                                     */
  277.  
  278.  
  279. int udp_close(u_short udp)
  280. {
  281. UDP_CTL *p_udpctl;
  282. UDP_CTL **pp_udpctl;
  283.  
  284.     if (udp >= udp_tablen) return(-1);
  285.     pp_udpctl = &udp_list;
  286.     p_udpctl = udp_list;
  287.     while(p_udpctl)
  288.     {
  289.         if(p_udpctl == udp_tab[udp])    /* found */
  290.         {
  291. #ifdef DEBUGCLS
  292. printf("UDP: close port %u\n",p_udpctl->lcl_port);
  293. #endif
  294.             *pp_udpctl = p_udpctl->next;    /* unlink from list */
  295.             if(p_udpctl->pkt)
  296.             {
  297.                 tm_stop(p_udpctl->udp_tm);
  298.                 ip_free(p_udpctl->pkt);
  299.             }
  300.             buf_free(udp_buffers,(char *)p_udpctl);
  301.             udp_tab[udp] = NULL;
  302.             return(udp);
  303.         }
  304.         pp_udpctl = &(p_udpctl->next);
  305.         p_udpctl = p_udpctl->next;
  306.     }
  307.     return(0);
  308. }
  309.     
  310.     
  311. int udp_open(u_short lcl_port,UDP_UPCALL upcall)
  312. {
  313. int i;
  314. UDP_CTL *p_udpctl;
  315.  
  316.     if(!lcl_port)
  317.         lcl_port = udp_newport();
  318. #ifdef DEBUGOPN
  319. printf("UDP: open port %u\n",lcl_port);
  320. #endif    
  321.     for(p_udpctl = udp_list; p_udpctl; p_udpctl = p_udpctl->next)
  322.     {
  323.         if(p_udpctl->lcl_port == lcl_port)
  324.         {
  325. #ifdef DEBUGOPN
  326. printf("UDP: port %u already in use\n",lcl_port);
  327. #endif    
  328.             return -1;
  329.         }
  330.     }
  331.     
  332.     for(i=0; i < udp_tablen; i++)
  333.         if(!udp_tab[i]) break;
  334.     if(i == udp_tablen)
  335.     {
  336. #ifdef DEBUGOPN
  337. printf("UDP: port table full\n");
  338. #endif    
  339.         return(-1);
  340.     }
  341.  
  342.  
  343.     p_udpctl = (UDP_CTL *)buf_alloc(udp_buffers,sizeof(UDP_CTL));
  344.     if(!p_udpctl)
  345.     {
  346. #ifdef DEBUGOPN
  347. printf("UDP: out of buffers\n");
  348. #endif    
  349.         return(-1);
  350.     }
  351.     udp_tab[i] = p_udpctl;
  352.  
  353.     p_udpctl->next = udp_list;
  354.     udp_list = p_udpctl;
  355.     
  356.     
  357.     p_udpctl->lcl_port = lcl_port;        /* fill in connection info */
  358.     p_udpctl->fgn_port = 0;
  359.     p_udpctl->fhost = 0L;
  360.     p_udpctl->upcall = upcall;
  361.     p_udpctl->pkt = NULL;
  362.     p_udpctl->data_len = 0;
  363.     p_udpctl->data = NULL;
  364.     p_udpctl->udp_err = UDP_OK;
  365.     
  366.     return(i);
  367. }
  368.  
  369.  
  370. int udp_write(u_short udp, char *data, u_short len, INADDR fhost, u_short port)
  371. {
  372. register UDP    *p_udp;
  373. TCP_PSEUDO          udp_ph;
  374. PACKET             *pkt;
  375. UDP_CTL            *p_udpctl;
  376. register int      udplen;
  377. u_short          csum;
  378. int              ret;
  379.  
  380.     if(udp >= udp_tablen || !udp_tab[udp] ||
  381.        !fhost || !port || !data)
  382.         return(-1);
  383.         
  384.     p_udpctl = udp_tab[udp];
  385.     if(p_udpctl->udp_err == UDP_NORECV) return(-1);
  386.  
  387.     udplen = len + (int)sizeof(UDP);
  388.     pkt = ip_alloc(udplen,0);
  389.     if(!pkt) return(-1);
  390.  
  391.     p_udp = (UDP *)ip_data(pkt);
  392.  
  393.     p_udp->length = udplen;
  394.     p_udp->src_port = p_udpctl->lcl_port;
  395.     p_udp->dst_port = port;
  396.     p_udp->chksum = 0;
  397.  
  398.     p_udpctl->fgn_port = port;
  399.     p_udpctl->fhost = fhost;
  400.  
  401.     udp_ph.src = ip_myaddr();
  402.     udp_ph.dst = fhost;
  403.     udp_ph.protocol = IP_UDP;
  404.     udp_ph.length = udplen;
  405.     
  406.     if(len) memcpy(udp_data(p_udp),data,len);        /* copy data */
  407.     
  408.     csum = ~chksum((u_short *)&udp_ph,(int)sizeof(TCP_PSEUDO),0);
  409.     p_udp->chksum = chksum((u_short *)p_udp,udp_ph.length,csum);
  410.  
  411.     udp_counts[1]++;
  412.  
  413.     ret = ip_send(IP_UDP,pkt,udp_ph.length,fhost);
  414.  
  415. #ifdef DEBUGWR
  416. printf("UDP: pkt[%d] %u to   %08lx.%u\n",udp_ph.length,p_udpctl->lcl_port,fhost,port);
  417. if(ret < 0) printf("ip_send: network error %d\n",ret);
  418. #endif
  419.     ip_free(pkt);
  420.     return(len);
  421. }
  422.  
  423.  
  424. u_short udp_newport(void)
  425. {
  426. static u_short udp_actport = 0;
  427.  
  428.     if(!udp_actport)
  429.     {
  430.         udp_actport = (u_short)clock();
  431.     }
  432.     else
  433.         udp_actport++;
  434.     if(udp_actport < 1200)
  435.         udp_actport += 1200;
  436.     return(udp_actport);
  437. }